package com.yb.custom.annotation.log.exception;

import com.yb.custom.annotation.log.controller.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局统一异常捕获处理类
 *
 * @author yangbiao
 * @date 2022/3/30
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(CustomException.class)
    public ResultVO<String> customException(CustomException e) {
        log.info(e.getMessage());
        //自定义异常都是抛出自己的提示信息,是可控的,是可以在页面显示的,
        //所以为了前端可以区分是否可以放心抛出提示,这里返回一个独特的响应码
        return ResultVO.customError(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResultVO<String> maxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        log.info(e.getMessage());
        return ResultVO.error("文件大小超过限制");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public ResultVO<String> bindException(BindException e) {
        log.info(e.getMessage());
        if (!CollectionUtils.isEmpty(e.getFieldErrors())) {
            String errorMessage = e.getFieldErrors().stream().map(s -> s.getDefaultMessage())
                    .collect(Collectors.joining(","));
            return ResultVO.error(errorMessage);
        }
        return ResultVO.error("网络异常");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public ResultVO constraintViolationExceptionHandler(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        if (!CollectionUtils.isEmpty(e.getConstraintViolations())) {
            String withMessage = e.getConstraintViolations()
                    .stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(","));
            return ResultVO.error(withMessage);
        }
        return ResultVO.error("网络异常");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        if (!CollectionUtils.isEmpty(e.getBindingResult().getFieldErrors())) {
            String errorMessage = e.getBindingResult().getFieldErrors().stream()
                    .map(fieldError -> fieldError.getDefaultMessage())
                    .collect(Collectors.joining(","));
            return ResultVO.error(errorMessage);
        }
        return ResultVO.error("网络异常");
    }

    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResultVO methodArgumentTypeMismatchExceptionHandler(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        return ResultVO.error(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public ResultVO methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException e) {
        log.error(e.getMessage(), e);
        return ResultVO.error("参数类型不匹配或参数有误");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ResultVO httpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        return ResultVO.error(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResultVO missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return ResultVO.error(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotWritableException.class)
    public ResultVO httpMessageNotWritableExceptionHandler(HttpMessageNotWritableException e) {
        log.error(e.getMessage(), e);
        return ResultVO.error(e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResultVO exceptionHandler(Exception e) {
        log.error(e.getMessage(), e);
        return ResultVO.error("网络繁忙...");
    }

}